<?php if (!defined('CORE_DIR')) die('Wrong entry point!');

/* 
 * Copyright 2010 Anton Muraviev a.k.a kuromaisu
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */


// =============================================================================
// Section: View
// =============================================================================
// 
// Configuration namespace:
// 	view
// 
// Configuration options:
// 	default_decorator		-	decorator that will be used (nothing by default)
// 	autoload				-	(array) libraries' Name => Path pairs that will 
// 								be injected into the rendered view, but only if
// 								they were already be loaded.

Aero::define('AeroView', AS_CLASS);

/* -----------------------------------------------------------------------------
 * Class: AeroView
 * -----------------------------------------------------------------------------
 * 
 * 
 * 
 */
class AeroView
{
	private $decorator;
	private $parameters;
	
	private $view_stack = array();
	private $nesting_level = 0;
	
	/*
	 * Constructor: __construct
	 */
	function __construct($parameters = array())
	{
		$this->decorator = Aero::option('view.default_decorator','');
		
		$this->parameters = $parameters;
		$this->parameters['View'] =& $this;
		
		// Load other singletons, if they were initialized
		$autoload = Aero::option('view.autoload',array(
			'Request' => 'libs/request',
			'Response' => 'libs/response',
		));
		
		foreach ($autoload as $name => $script)
		{
			if (Aero::isInitialized($script))
			{
				$this->parameters[$name] = Aero::load($script);
			}
		}
		
	}
	
	/*
	 * Method: decorateWith
	 *
	 */
	public function decorateWith($decorator_path)
	{
		$this->decorator = $decorator_path;
	}
	
	/*
	 * Method: content
	 *
	 */
	public function content()
	{
		if (count($this->view_stack) > 0)
		{
			return array_pop($this->view_stack);
		}
		
		throw new ErrorException('<code>AeroView::content()</code> was called more than once', 0, E_USER_ERROR);
	}
	
	/*
	 * Method: nestingLevel
	 *
	 */
	public function nestingLevel()
	{
		return $this->nesting_level;
	}
	
	/*
	 * Method: parameter
	 * 
	 */
	public function parameter($name, $default = null)
	{
		if (isset($this->parameters[$name]))
		{
			return $this->parameters[$name];
		}
		
		return $default;
	}
	
	/*
	 * Method: setParameter
	 * 
	 */
	public function setParameter($name, $value = null)
	{
		if (!array($name))
		{
			$name = array($name => $value);
		}
		
		foreach ($name as $key => $value)
		{
			$this->parameters[$key] = $value;
		}
	}
	
	/*
	 * Method: unsetParameter
	 * 
	 */
	public function unsetParameter($name)
	{
		if (!array($name))
		{
			$name = array($name);
		}
		
		foreach ($name as $_name)
		{
			unset($this->parameters[$_name]);
		}
	}
	
	/*
	 * Method: load
	 *
	 */
	public function load($path, $parameters = array())
	{
		$this->parameters = array_merge($this->parameters, $parameters);
		$parameters =& $this->parameters;
		$_decorator = $this->decorator;
		$output = Aero::run($path, $parameters, true);
		
		if ($this->decorator !== $_decorator)
		{
			$this->nesting_level++;
			$nl = count($this->view_stack);
			
			array_push($this->view_stack,$output);
			
			$output = $this->load($this->decorator);
			
			$this->nesting_level--;
			
			if ($nl !== count($this->view_stack))
			{
				throw new ErrorException('<code>AeroView::content()</code> must be called exactly once in <span class="path">' . $this->decorator . EXT . '</span>', 0, E_USER_ERROR);
			}
			
			$this->decorator = $_decorator;
		}
		
		return $output;
	}

}
